#ifndef WIDGET_H
#define WIDGET_H

extern "C"
{
#define UINT64_C(c)     c ## ULL
#include "libavformat/avformat.h"
#include "libavutil/avstring.h"
#include "libavutil/pixdesc.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/audioconvert.h"
#include "libavcodec/colorspace.h"
#include "libavcodec/opt.h"
#include "libavcodec/avfft.h"

#if 0x0
#include <SDL/SDL.h>
#ifdef __MINGW32__
#undef main /* We don't want SDL to override our main() */
#endif
#endif

}

#define SDL_AUDIO_BUFFER_SIZE 1024


#include <QtCore>
#include <QtGui>
#include "dsound.h"
#include <my_SDL_audio.h>
#include "my_SDL_sysaudio.h"


class T_MutexLocker
{
public:
    QMutex *m_mutex;
    explicit T_MutexLocker(QMutex *a_mutex) : m_mutex(a_mutex)
    {
        m_mutex->lock();
    }
    ~T_MutexLocker()
    {
        m_mutex->unlock();
    }
};

class T_FPS
{
public:
    QTime m_time_line;
    double m_fps;
    int m_count;
    explicit T_FPS() : m_fps(0), m_count(0)
    {
    }
    bool wake()
    {
        if(!m_time_line.isNull()) return false;
        m_time_line.start();
        return true;
    }
    void restart()
    {
        m_count = 0;
        m_time_line.start();
    }
    void add(int a)
    {
        m_count += a;
    }
    double value()
    {
        if(m_time_line.isNull())
        {
            qDebug() << "[T_FPS.value()] warning: T_FPS.wake() was not called.";
            return 0;
        }
        else if(m_time_line.elapsed() < 1000)
        {
            return m_fps;
        }
        else
        {
            m_fps = 1000.0 * m_count / m_time_line.elapsed();
            restart();
            return m_fps;
        }
    }
};

class T_AVPicture
{
public:
    AVPicture m_av_picture;
    enum PixelFormat m_pix_fmt;
    int m_width;
    int m_height;
    int m_numBytes;
    uint8_t *m_buffer;

    explicit T_AVPicture(PixelFormat a_pix_fmt, int a_width, int a_height)
        :
        m_pix_fmt(a_pix_fmt),
        m_width(a_width),
        m_height(a_height),
        m_numBytes(0),
        m_buffer(0)
    {
        reinit();
    }
    ~T_AVPicture()
    {
        if(m_buffer) delete[] m_buffer;
    }
    void resize(int a_width, int a_height)
    {
        if(m_width==a_width && m_height==a_height) return;
        m_width = a_width;
        m_height = a_height;
        reinit();
    }
protected:
    void reinit()
    {
        int v_numBytes=avpicture_get_size(
                m_pix_fmt,
                m_width,
                m_height
                );
        //qDebug() << "[v_numBytes][m_numBytes]" << v_numBytes << m_numBytes;
        if(m_numBytes < v_numBytes)
        {
            m_numBytes = v_numBytes;
            //qDebug() << "[m_numBytes]" << m_numBytes;
            if(m_buffer) delete[] m_buffer;
            m_buffer=new uint8_t[m_numBytes];
        }
        avpicture_fill(
                &m_av_picture,
                m_buffer,
                m_pix_fmt,
                m_width,
                m_height
                );
    }
};

class T_AVPacket
{
public:
    int m_frame_no;
    AVPacket m_av_packet;
};

class Widget;
class T_AudioThread : public QThread
{
public:
    Widget *m_widget;
    explicit T_AudioThread(Widget *a_widget)
        : m_widget(a_widget)
    {
    }

    virtual void run();
};

namespace Ui {
    class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
public:
    AVFormatContext	*formatCtx;
    int	videoStream;
    int audioStream;
    AVCodecContext	*videoCtx;
    AVCodecContext	*audioCtx;
    AVCodec		*videoCodec;
    AVCodec		*audioCodec;
    AVFrame		*frame;
    int		frameFinished;
    QString		filename;
    int frameNo;
    QTimer m_timer;
    QImage m_displayBuffer;
    T_AVPicture *m_av_picture;
    QTime m_time_line;
    int m_drop_count;
    AVStream *m_v_stream;
    T_FPS m_fps1;
    T_FPS m_fps2;
    QQueue<T_AVPacket> m_video_packet_queue;
    QQueue<T_AVPacket> m_audio_packet_queue;
    QMutex m_display_mutex;
    QMutex m_frame_mutex;
    int current_index;  // 同上. バッファー上の現在位置.
    int loaded_size;  // 同上. バッファーに読み込まれているデータサイズ.
    quint8* buffer[SDL_AUDIO_BUFFER_SIZE];  // 同上. decodeFrame() と同じもの.
    T_AVPacket m_audio_temp;
    QByteArray m_audio_buffer;
    DECLARE_ALIGNED(16,uint8_t,m_audio_decode_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    DECLARE_ALIGNED(16,uint8_t,m_audio_convert_array)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    int m_audio_elapsed;

    //LPDIRECTSOUND lpDSO;
    //LPDIRECTSOUNDBUFFER mixbuf;
    //Uint8 *locked_buf;
    //int mixlen;
    //DWORD lastchunk;
    //int NUM_BUFFERS;
    SDL_AudioDevice *v_audio_dev;

protected slots:
    void onTimerTimeout();

public:
    T_AudioThread m_audio_thread;
    virtual void sdl_audio_callback(Uint8 *stream, int len);
    //virtual int decodeFrame(Uint8* buffer, int buffer_size);
    //Uint8 *DX5_GetAudioBuf();
    //void DX5_PlayAudio();
    //void DX5_WaitAudio_BusyWait();
    //void DX6_WaitAudio_EventWait();
protected:
    virtual void paintEvent(QPaintEvent *e)
    {
        QPainter v_p(this);
        int v_font_size = 16;
        QFont v_f("MS UI Gothic", v_font_size, QFont::Bold);
        //QFontInfo fi(v_f);
        //qDebug() << fi.fixedPitch();
        v_f.setFixedPitch(true);
        v_p.setFont(v_f);
        m_display_mutex.lock();
        v_p.drawImage(QPoint(0, 0), m_displayBuffer);
        m_display_mutex.unlock();
        QTime v_elapsed(0, 0, 0, 0);
        v_elapsed = v_elapsed.addMSecs(m_time_line.elapsed());
        QString v_msg = QString("E=%1 F=%2 D=%3")
                        .arg(v_elapsed.toString("hh:mm:ss[zzz]"))
                        .arg(frameNo)
                        .arg(m_drop_count)
                        ;
        //[Time etc]
        int v_diff = 1;
        int v_x_off = 2;
        int v_y_off = this->height() - 4;
        v_p.setPen(Qt::white);
        v_p.drawText(QPoint(v_x_off+v_diff, v_y_off+v_diff), v_msg);
        v_p.setPen(Qt::black);
        v_p.drawText(QPoint(v_x_off, v_y_off), v_msg);
        //[FPS]
        v_x_off = 2;
        v_y_off = v_font_size + 4;
        //v_msg = QString("%1 fps").arg(m_fps);
        //v_msg = QString("%1 fps : %2 fps").arg(m_fps).arg(m_fps2.value());
        v_msg = QString("%1 fps : %2 fps")
                .arg(m_fps1.value(), 6, 'f', 2, ' ')
                .arg(m_fps2.value(), 6, 'f', 2, ' ');
        v_p.setPen(Qt::white);
        v_p.drawText(QPoint(v_x_off+v_diff, v_y_off+v_diff), v_msg);
        v_p.setPen(Qt::black);
        v_p.drawText(QPoint(v_x_off, v_y_off), v_msg);
    }
#if 0x0
    QFontDatabase fdb;
    QStringList fl = fdb.families();
    qDebug() << fl;
    ("Arial", "Arial Black", "Arial Narrow", "Batang", "BatangChe", "Book Antiqua", "Bookman Old Style", "Century", "Century Gothic", "Comic Sans MS", "Courier", "Courier New", "Dotum", "DotumChe", "Estrangelo Edessa", "FixedSys", "Franklin Gothic Medium", "Garamond", "Gautami", "Georgia", "Gulim", "GulimChe", "Gungsuh", "GungsuhChe", "Haettenschweiler", "HGP創英角ｺﾞｼｯｸUB", "HGP創英角ﾎﾟｯﾌﾟ体", "HGPｺﾞｼｯｸE", "HGS創英角ｺﾞｼｯｸUB", "HGS創英角ﾎﾟｯﾌﾟ体", "HGSｺﾞｼｯｸE", "HG丸ｺﾞｼｯｸM-PRO", "HG創英角ｺﾞｼｯｸUB", "HG創英角ﾎﾟｯﾌﾟ体", "HG正楷書体-PRO", "HGｺﾞｼｯｸE", "Impact", "Latha", "Lucida Console", "Lucida Sans Unicode", "Mangal", "Marlett", "Microsoft Sans Serif", "MingLiU", "Modern", "Monotype Corsiva", "MS Sans Serif", "MS Serif", "MS UI Gothic", "MV Boli", "Nina", "NSimSun", "OCRB", "Palatino Linotype", "PMingLiU", "Raavi", "Roman", "Script", "Shruti", "SimHei", "SimSun", "Small Fonts", "Sylfaen", "Symbol", "System", "Tahoma", "Terminal", "Times New Roman", "Trebuchet MS", "Tunga", "Verdana", "Webdings", "Wingdings", "Wingdings 2", "Wingdings 3", "ＭＳ ゴシック", "ＭＳ 明朝", "ＭＳ Ｐゴシック", "ＭＳ Ｐ明朝")
#endif

};

#endif // WIDGET_H
